不再限制一個工廠(物件)建立許多產品(物件),而是轉變成一個產品(物件)對應一個工廠(物件),而決定生產哪個產品(物件)則轉交給另一個決策者(物件)。
昨天提到,每次新增一個產品時,Simple Factory Method 內負責管理生產的工廠就必須「變動 switch-case」,此項舉動違反 SOLID 的 OCP。Factory Method 改良這一點,讓每項產品擁有各自的工廠。實際決定要使用哪間工廠的決策者,則轉交給其他物件負責,本身不涉入生產判定。
Factory Method 的作法是:
Class、Abstract Class 或 Interface。Interface。產品親代:PETBottle
public abstract class PETBottle {
    protected String smell = "";
    protected String color = "";
    public PETBottle(String smell, String color) {
        this.smell = smell;
        this.color = color;
    }
    public abstract String getTaste();
}
產品子代:Coke、Water、OrangeJuice
public class Coke extends PETBottle {
    public Coke(String smell, String color) {
        super(smell, color);
    }
    @Override
    public String getTaste() {
        return "這瓶可樂的顏色:" + color + ",香味是:" + smell;
    }
}
public class Water extends PETBottle {
    public Water(String smell, String color) {
        super(smell, color);
    }
    @Override
    public String getTaste() {
        return "這瓶水的顏色:" + color + ",香味是:" + smell;
    }
}
public class OrangeJuice extends PETBottle {
    public OrangeJuice(String smell, String color) {
        super(smell, color);
    }
    @Override
    public String getTaste() {
        return "這瓶柳橙汁的顏色:" + color + ",香味是:" + smell;
    }
}
工廠親代:PETBottleFactory
public interface PETBottleFactory {
    public PETBottle getPET_Bottle();
}
工廠子代:CokeFactory、WaterFactory、OrangeJuiceFactory
public class CokeFactory implements PETBottleFactory {
    @Override
    public PETBottle getPET_Bottle() {
        System.out.println("機器選定可樂瓶子");
        System.out.println("黑色液體衝入瓶子內");
        System.out.println("轉上瓶蓋,完成");
        return new Coke("甜甜的", "黑色");
    }
}
public class OrangeJuiceFactory implements PETBottleFactory {
    @Override
    public PETBottle getPET_Bottle() {
        System.out.println("機器選定礦泉柳橙汁瓶子");
        System.out.println("橘色液體衝入瓶子內");
        System.out.println("轉上瓶蓋,完成");
        return new OrangeJuice("酸酸的", "橘色");
    }
}
public class WaterFactory implements PETBottleFactory {
    @Override
    public PETBottle getPET_Bottle() {
        System.out.println("機器選定礦泉水瓶子");
        System.out.println("透明液體衝入瓶子內");
        System.out.println("轉上瓶蓋,完成");
        return new Water("無味", "透明的");
    }
}
決策者:
public class PETBottleFactoryMethodSample {
    public static void main(String[] args) {
        System.out.println("今天我想來點,可樂!");
        PETBottleFactory cokeFactory = new CokeFactory();
        PETBottle coke = cokeFactory.getPET_Bottle();
        System.out.println("得到一瓶可樂!");
        System.out.println(coke.getTaste());
        System.out.println("---咳咳咳---");
        System.out.println("有點甜,我想喝點,礦泉水!");
        PETBottleFactory waterFactory = new WaterFactory();
        PETBottle water = waterFactory.getPET_Bottle();
        System.out.println("得到一瓶礦泉水!");
        System.out.println(water.getTaste());
        System.out.println("---咕嚕咕嚕---");
        System.out.println("清爽!最來來點,柳橙汁!");
        PETBottleFactory orangeJuiceFactory = new OrangeJuiceFactory();
        PETBottle orangeJuice = orangeJuiceFactory.getPET_Bottle();
        System.out.println("得到一瓶柳橙汁!");
        System.out.println(orangeJuice.getTaste());
    }
}
受限於 JavaScript 沒有虛擬型別、無法限制型別。
產品親代:PETBottle
/** @abstract */
class PETBottle {
  constructor(smell, color) {
    this.smell = smell;
    this.color = color;
  }
  getTaste() { return; }
}
產品子代:Coke、Water、OrangeJuice
class Coke extends PETBottle {
  constructor(smell, color) {
    super(smell, color);
  }
  /** @override */
  getTaste() {
    return "這瓶可樂的顏色:" + this.color + ",香味是:" + this.smell;
  }
}
class Water extends PETBottle {
  constructor(smell, color) {
    super(smell, color);
  }
  /** @override */
  getTaste() {
    return "這瓶水的顏色:" + this.color + ",香味是:" + this.smell;
  }
}
class OrangeJuice extends PETBottle {
  constructor(smell, color) {
    super(smell, color);
  }
  /** @override */
  getTaste() {
    return "這瓶柳橙汁的顏色:" + this.color + ",香味是:" + this.smell;
  }
}
工廠親代:PETBottleFactory
/** @interface */
class PETBottleFactory {
  getPET_Bottle() { return; }
}
工廠子代:CokeFactory、WaterFactory、OrangeJuiceFactory
class CokeFactory extends PETBottleFactory {
  /** @override */
  getPET_Bottle() {
    console.log("機器選定可樂瓶子");
    console.log("黑色液體衝入瓶子內");
    console.log("轉上瓶蓋,完成");
    return new Coke("甜甜的", "黑色");
  }
}
class WaterFactory extends PETBottleFactory {
  /** @override */
  getPET_Bottle() {
    console.log("機器選定礦泉水瓶子");
    console.log("透明液體衝入瓶子內");
    console.log("轉上瓶蓋,完成");
    return new Coke("甜甜的", "黑色");
  }
}
class OrangeJuiceFactory extends PETBottleFactory {
  /** @override */
  getPET_Bottle() {
    console.log("機器選定礦泉柳橙汁瓶子");
    console.log("橘色液體衝入瓶子內");
    console.log("轉上瓶蓋,完成");
    return new OrangeJuice("酸酸的", "橘色");
  }
}
決策者:
const PETBottleFactoryMethodSample = () => {
  console.log("今天我想來點,可樂!");
  const cokeFactory = new CokeFactory();
  const coke = cokeFactory.getPET_Bottle();
  console.log("得到一瓶可樂!");
  console.log(coke.getTaste());
  console.log("---咳咳咳---");
  console.log("有點甜,我想喝點,礦泉水!");
  const waterFactory = new WaterFactory();
  const water = waterFactory.getPET_Bottle();
  console.log("得到一瓶礦泉水!");
  console.log(water.getTaste());
  console.log("---咕嚕咕嚕---");
  console.log("清爽!最來來點,柳橙汁!");
  const orangeJuiceFactory = new OrangeJuiceFactory();
  const orangeJuice = orangeJuiceFactory.getPET_Bottle();
  console.log("得到一瓶柳橙汁!");
  console.log(orangeJuice.getTaste());
};
PETBottleFactoryMethodSample();
Factory Method 改善了 Simple Factory Method 無法遵守 SOLID 的問題,將「選擇」交給決策者,本身不涉及選擇,只負責生產。
然而,這個生產是直線關係,工廠對應產品,假如生產的產品數量增加非常多時,整體程式會顯得笨重、重複。此時,如果能找出產品之間的共通點,那就能抽離出來,重構後變成新的 Factory 模式。
明天,將介紹 Abstract Factory 模式。